//
// Created by denglibin on 19-10-29.
//
/**
 * epoll基于非阻塞I/O事件驱动
 **/

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>

#define MAX_EVENTS 1024 /*最大客户端数量*/
#define BUFLEN 128
#define SERV_PORT 8080

/**
 *status: 1表示在监听事件中，0表示不在
 *last_active: 记录最后一次相应时间，做超时处理
 * */
struct myevent_s {
    int fd;
    int events;
    void* arg;
    void (*call_back)(int fd, int events, void* arg);
    int status;
    char buf[BUFLEN];
    int len;
    long last_active;
};

int g_efd; /*epoll_create返回的句柄*/
struct myevent_s g_events[MAX_EVENTS + 1];/* +1 最后一个用于server_fd*/

/**
 *设置为非阻塞
 **/
static int  setnonblocking(int sockFd){
    if(fcntl(sockFd, F_SETFL, fcntl(sockFd, F_GETFD,0)|O_NONBLOCK) == -1){
        return -1;
    }
    return 0;
}

static void del_client_fd(int fd){
    epoll_ctl(g_efd, EPOLL_CTL_DEL, fd, NULL);
}
static void recvdata(int fd, int events, void * arg);

/**
 * 设置myevent_s相关属性
 * @param ev
 * @param fd
 * @param call_back
 * @param arg
 */
static void eventset(struct myevent_s *ev, int fd, void (*call_back)(int, int, void *),void *arg){
    ev->fd = fd;
    ev->call_back = call_back;
    ev->arg = arg;
    if(ev->status != 1){ //为1表示正在监控中
        ev->status = 0;
    }
    ev->last_active = time(NULL);
}
/**
 *绑定事件
 **/
static void eventadd(int efd, int events, struct myevent_s * myevent){
    myevent->events = events;
    struct epoll_event ev;
    ev.events = events;
    ev.data.ptr = myevent;
    int res;
    if(myevent->status == 1){ // 在监控中
        res = epoll_ctl(efd, EPOLL_CTL_MOD, myevent->fd, &ev);
    } else {
        res = epoll_ctl(efd, EPOLL_CTL_ADD, myevent->fd, &ev);
    }
    if(res < 0){
        perror("epoll_ctl:");
        exit(-1);
    } else {
        myevent->status = 1;
        printf("eventadd  ok fd=%d, events=%0x\n", myevent->fd, events);
    }


}
/**
 * 发送数据回调
 **/
static void send_data(int fd, int events, void * arg){
    struct myevent_s * ev = (struct myevent_s*)arg;
    int n = ev->len;
    if(n > 0){
        eventset(ev, fd, recvdata, ev);
        eventadd(g_efd, EPOLLIN, ev);
    } else {
        close(fd);
        del_client_fd(fd);
        perror("send:");
    }
}
/**
 * 连接有数据可读时的回调函数
 * @param fd
 * @param events
 * @param arg
 */
 void recvdata(int fd, int events, void * arg){
    struct myevent_s * ev = (struct myevent_s*)arg;
    int n;
    bzero(ev->buf, sizeof(ev->buf));
    n = recv(fd, ev->buf, sizeof(ev->buf), 0);

    if(n > 0){
        printf("receive data: %s", ev->buf);
        ev->len = n;
        printf("status = %d\n", ev->status);
        eventset(ev, fd, send_data, ev); //设置属性
        eventadd(g_efd, EPOLLOUT,ev); // 事件绑定
        n = send(fd, ev->buf, ev->len, 0); // 再发送给客户端
        ev->len = n;
    } else if(n == 0){
        del_client_fd(fd);
        close(fd);
        ev->status = 0;
        printf("client disconnect, fd:%d\n", fd);
    }
}

/**
 * 新的连接到达时的回调函数
 **/
static void new_conn(int fd, int events, void * arg){
    struct sockaddr_in cin; // 存客户端地址
    socklen_t  len = sizeof(cin);
    int cfd, i;
    /*获取连接*/
    cfd = accept(fd, (struct sockaddr *) &cin, &len);
    if(cfd < 0){
        if(errno != EAGAIN && errno != EINTR){
            /*暂时不作处理*/
        } else {
            printf("%s accept error %s\n", __func__, strerror(errno));
            return;
        }
    }

    for(i = 0; i < MAX_EVENTS; i++) { //找到一个空位
        if(g_events[i].status == 0){
            break;
        }
    }
    if(i == MAX_EVENTS){ // 达到最大连接数了
        printf("max connection limit %d\n", MAX_EVENTS);
        return;
    }
    if(setnonblocking(cfd) < 0){
        perror("fcntl nonblocking failed");
        return;
    }
    eventset(g_events + i, cfd, recvdata, g_events + i);// 设置属性
    eventadd(g_efd, EPOLLIN, g_events + i); //事件绑定
    printf("new connection %s:%d, time:%ld, pos: \n", inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), g_events[i].last_active, i);

}

static void initlistensocket(int epoll_fd, int port){
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    setnonblocking(lfd);

    eventset(&g_events[MAX_EVENTS], lfd, new_conn, &g_events[MAX_EVENTS]);
    eventadd(epoll_fd, EPOLLIN, &g_events[MAX_EVENTS]);

    /*设置服务端地址和端口*/
    struct sockaddr_in sin;
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);

    /*绑定到socket*/
    bind(lfd, (struct sockaddr*) &sin, sizeof(sin));
    /*监听*/
    listen(lfd, 20);

}

static int main_(void){

    g_efd = epoll_create(MAX_EVENTS+1);
    if(g_efd < 0){
        perror("epoll_create:");
        exit(-1);
    }
    initlistensocket(g_efd, SERV_PORT);
    /*事件循环*/
    struct epoll_event re_events[MAX_EVENTS + 1];
    printf("server running port: %d\n", SERV_PORT);
    int i;
    while (1){
        long now = time(NULL);

        /*等待事件*/
        int fd_num = epoll_wait(g_efd, re_events, MAX_EVENTS + 1, 1000);
        if(fd_num < 0){
            perror("epoll_wait:");
            break;
        }
        for(i = 0; i < fd_num; i++){
            struct myevent_s * ev = (struct myevent_s *)re_events[i].data.ptr;
            /*读就绪*/
            if((re_events[i].events & EPOLLIN) && (ev->events & EPOLLIN)){
                ev->call_back(ev->fd, ev->events, ev->arg);
            }
            /*写就绪*/
            if((re_events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)){
                ev->call_back(ev->fd, ev->events, ev->arg);
            }
        }
    }
}